package sshMutual

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/gorilla/websocket"
	uuid "github.com/satori/go.uuid"
)

//创建客户端管理者
var manager = ClientManager{
	register:   make(chan *Client),
	unregister: make(chan *Client),
	clients:    make(map[*Client]bool),
}

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func (manager *ClientManager) start() {
	for {

		select {
		//如果有新的连接接入,就通过channel把连接传递给conn
		case conn := <-manager.register:
			//把客户端的连接设置为true
			manager.clients[conn] = true
			//把返回连接成功的消息json格式化
			log.Println(conn.id, "连接成功")

			conn.send <- []byte(fmt.Sprintf("连接成功 当前在线用户 %d", len(manager.clients)))

			//调用客户端的send方法，发送消息
			go manager.send(conn)
			//如果连接断开了

		case conn := <-manager.unregister:
			//判断连接的状态，如果是true,就关闭send，删除连接client的值

			if _, ok := manager.clients[conn]; ok {

				log.Println("关闭连接", conn.id)
				if conn.ssh_client.cli != nil {
					log.Println("close ssh")
					conn.ssh_client.cli.Close()
				}
				if conn.ssh_client.userinfo.LocalMode == "yes" {
					log.Println("close cmd")
					conn.ssh_client.ptmx.Close()
				}

				conn.send <- []byte(fmt.Sprintf("断开成功 当前在线用户 %d", len(manager.clients)))

				conn.socket.Close()
				close(conn.send)
				delete(manager.clients, conn)
				log.Println(manager.clients)

			}
		}
	}
}

//定义客户端管理的send方法
func (manager *ClientManager) send(c *Client) {
	for {

		buf := make([]byte, 4096)
		if c.ssh_client.userinfo.LocalMode == "yes" {

			if n1, err := c.ssh_client.ptmx.Read(buf); err != nil {
				manager.unregister <- c
				break

			} else {

				c.send <- buf[:n1]
			}

		} else {

			if n1, err := c.ssh_client.Stdout.Read(buf); err != nil {
				manager.unregister <- c
				break

			} else {

				c.send <- buf[:n1]
			}

		}

	}
}

//定义客户端结构体的read方法
func (c *Client) read() {
	defer func() {
		manager.unregister <- c
		c.socket.Close()
	}()
	for {
		//读取消息
		_, message, err := c.socket.ReadMessage()
		//如果有错误信息，就注销这个连接然后关闭
		if err != nil {
			manager.unregister <- c
			c.socket.Close()
			break
		}
		if c.ssh_client.userinfo.LocalMode == "yes" {
			go io.Copy(c.ssh_client.ptmx, strings.NewReader(string(message)))

		} else {

			go io.Copy(c.ssh_client.Stdin, strings.NewReader(string(message)))

		}

	}

}

func (c *Client) write() {
	defer func() {
		c.socket.Close()
	}()

	for {
		select {
		//从send里读消息
		case message, ok := <-c.send:
			//如果没有消息
			if !ok {
				c.socket.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}
			c.socket.WriteMessage(websocket.TextMessage, message)
		}
	}
}

func ConnectServer(w http.ResponseWriter, req *http.Request) {
	s := &socketConn{}
	s.Conn, s.err = upgrader.Upgrade(w, req, nil)

	uuids := uuid.NewV4().String()

	webclient := &Client{id: uuids, socket: s.Conn, send: make(chan []byte)}

	_, s.p, s.err = webclient.socket.ReadMessage()
	u := userinfo{}

	if s.err = json.Unmarshal(s.p, &u); s.err != nil {
		log.Println(s.err)

	} else {

		webclient.ssh_client = &ssh_client{userinfo: u}
		log.Println("传入信息", u, webclient.ssh_client.userinfo.LocalMode)
		if webclient.ssh_client.userinfo.LocalMode == "yes" {
			log.Println("本地模式", u.LocalMode)
			go webclient.ssh_client.NewLocalHost(u.Cmd[0], u.Cmd[1:]...)

			manager.register <- webclient
			time.Sleep(2 * time.Second)
			//启动协程收web端传过来的消息
			go webclient.read()
			//启动协程把消息返回给web端
			go webclient.write()
		} else {
			log.Println("远程模式", u.LocalMode)

			if webclient.ssh_client.Ping() {

				go webclient.ssh_client.NewSession(u.Cmd[0])
				manager.register <- webclient
				time.Sleep(2 * time.Second)
				go webclient.read()
				//启动协程把消息返回给web端
				go webclient.write()

			} else {
				manager.clients[webclient] = true
				manager.unregister <- webclient
				webclient.socket.WriteMessage(websocket.TextMessage, []byte("连接失败"))
				webclient.socket.Close()

			}

		}
	}

}
func NewConnectServer() {
	go manager.start()

	log.Println("启动服务websocket会话连接服务", "0.0.0.0:3002")
	http.HandleFunc("/", ConnectServer)
	http.ListenAndServe("0.0.0.0:3002", nil)

}
